#include "ASScrollText.h"

#define AS_MAX_SCROLLTEXT_CTRLS 256
#define AS_SCROLLTEXT_PAINT_GAP 30
#define AS_SCROLLTEXT_STEP 3

#define AS_SCROLLTEXT_TRUNCATE_TAIL "..."


//this array store all created as_scroll text controls ,just for use functions about timer.
static as_scrolltext* s_as_scrolltext_ctrl_store[AS_MAX_SCROLLTEXT_CTRLS];


static as_ret as_ctrl_scrolltext_store_ptr(as_scrolltext* ctrl_scrolltext_p)
{
    ASINT i = 0;
    as_ret ret = AS_OK;

    if(!ctrl_scrolltext_p)
    {
        //warning
        ret = AS_INVALID_PARAM;
        return ret;
    }

    for(i = 0; i < AS_MAX_SCROLLTEXT_CTRLS; i++)
    {
        if(s_as_scrolltext_ctrl_store[i] == NULL)
        {
            s_as_scrolltext_ctrl_store[i] = ctrl_scrolltext_p;
            break;
        }
    }

    if(i == AS_MAX_SCROLLTEXT_CTRLS)
    {
        //warning
        ret = AS_MEMORY_NOT_ENOUGH;
        return ret;
    }

    return ret;
}

static void as_ctrl_scrolltext_remove_ptr(as_scrolltext* ctrl_scrolltext_p)
{
    ASINT i = 0;

    if(!ctrl_scrolltext_p)
    {
        //warning
        return;
    }

    for(i = 0; i < AS_MAX_SCROLLTEXT_CTRLS; i++)
    {
        if(s_as_scrolltext_ctrl_store[i] == ctrl_scrolltext_p)
        {
            s_as_scrolltext_ctrl_store[i] = NULL;
            break;
        }
    }
}

static ASINT as_ctrl_scrolltext_get_wstr_width(as_scrolltext* scrolltext_p)
{
    if(scrolltext_p->if_small)
        return as_get_wstr_width_sf(scrolltext_p->text);
    else
        return as_get_wstr_width(scrolltext_p->text);
}

static ASINT as_ctrl_scrolltext_get_wstr_height(as_scrolltext* scrolltext_p)
{
    if(scrolltext_p->if_small)
        return as_get_wstr_height_sf(scrolltext_p->text);
    else
        return as_get_wstr_height(scrolltext_p->text);
}

static void as_ctrl_scrolltext_paint_truncated(as_scrolltext* scrolltext_p, as_rect* area_p, ASUINT text_color, ASINT text_h)
{
    ASINT x, y, truncated_len, i = 0, layer, print_len = 0;
    ASWSTR truncated_str;
    static ASWCHAR print_buf[64];
    ASUINT8* paint_buf;
    as_rect gclip;

    if(!scrolltext_p)
        return;

    layer = scrolltext_p->base.show_hdlr;
    paint_buf = as_get_layer_buffer_by_hdlr(layer);
    y = area_p->y + ((area_p->h - text_h) >> 1);

    //paint bg
    if(scrolltext_p->bg_img)
    {
        scrolltext_p->bg_img->base.paint_hdlr((as_control*)scrolltext_p->bg_img);
    }
    else
    {
        as_fill_rect(area_p, scrolltext_p->bg_color, scrolltext_p->bg_color);
    }

    if(layer < 0 || as_set_layer_clip_ex(layer, area_p) == AS_IGNORE
       || as_set_layer_clip_ex(layer, &scrolltext_p->valid_show_area) == AS_IGNORE)
    {
        as_reset_layer_clip(layer);
#if defined(AS_RUN_ON_SKY)
        as_reset_clip();
#endif
        return;
    }

    //paint text
    memset(print_buf, 0, sizeof(print_buf));
    truncated_str = as_ucs2_from_gb2312(AS_SCROLLTEXT_TRUNCATE_TAIL);

    if(scrolltext_p->if_small)
        truncated_len = as_get_wstr_width_sf(truncated_str);
    else
        truncated_len = as_get_wstr_width(truncated_str);

    if(scrolltext_p->text_paint_len /*+ truncated_len*/ < area_p->w)
    {
        x = area_p->x /*+ ((area_p->w - scrolltext_p->text_paint_len) >> 1)*/;
        as_get_global_clip(&gclip);

        if(scrolltext_p->if_small)
            as_draw_text_clip_sf(scrolltext_p->text, x, y, &gclip, text_color);
        else
            as_draw_text_clip(scrolltext_p->text, x, y, &gclip, text_color);
    }
    else
    {
        while(print_len < area_p->w - truncated_len)
        {
            *(print_buf + i) = *(scrolltext_p->text + i);

            if(*(print_buf + i) == 0)
                break;

            ++i;

            if(scrolltext_p->if_small)
                print_len = as_get_wstr_width_sf(print_buf);
            else
                print_len = as_get_wstr_width(print_buf);
        }

        if(print_len + truncated_len > area_p->w)
        {
            *(print_buf + i - 1) = 0;
        }

        as_wstrcat(print_buf, truncated_str);

        if(scrolltext_p->if_small)
            truncated_len = as_get_wstr_width_sf(print_buf);
        else
            truncated_len = as_get_wstr_width(print_buf);

        x = area_p->x/* + ((area_p->w - truncated_len) >> 1)*/;
        as_get_global_clip(&gclip);

        if(scrolltext_p->if_small)
            as_draw_text_clip_sf(print_buf, x, y, &gclip, text_color);
        else
            as_draw_text_clip(print_buf, x, y, &gclip, text_color);
    }
}

static void as_ctrl_scrolltext_paint_scrolled(as_scrolltext* scrolltext_p, as_rect* area_p,
        ASUINT text_color, ASINT text_h)
{
    ASINT x, y, layer;
    as_rect gclip;
    ASUINT8* paint_buf;

    if(!scrolltext_p)
        return;

    y = area_p->y + ((area_p->h - text_h) >> 1);
    layer = scrolltext_p->base.show_hdlr;
    paint_buf = as_get_layer_buffer_by_hdlr(scrolltext_p->base.show_hdlr);

    //paint focus bg
    if(scrolltext_p->focus_bg_img)
    {
        scrolltext_p->focus_bg_img->base.paint_hdlr((as_control*)scrolltext_p->focus_bg_img);
    }
    else
    {
        as_fill_rect(area_p, scrolltext_p->focus_bg_color, scrolltext_p->focus_bg_color);
    }

    if(layer < 0 || as_set_layer_clip_ex(layer, area_p) == AS_IGNORE
       || as_set_layer_clip_ex(layer, &scrolltext_p->valid_show_area) == AS_IGNORE)
    {
        as_reset_layer_clip(layer);
#if defined(AS_RUN_ON_SKY)
        as_reset_clip();
#endif
        return;
    }

    as_get_global_clip(&gclip);

    //paint text
    if(scrolltext_p->text_paint_len < area_p->w)
    {
        x = area_p->x/* + ((area_p->w - scrolltext_p->text_paint_len) >> 1)*/;

        if(scrolltext_p->if_small)
            as_draw_text_clip_sf(scrolltext_p->text, x, y, &gclip, text_color);
        else
            as_draw_text_clip(scrolltext_p->text, x, y, &gclip, text_color);
    }
    else
    {
        if(scrolltext_p->off_set <= 0 && scrolltext_p->off_set >= area_p->w - scrolltext_p->text_paint_len - AS_SCROLLTEXT_PAINT_GAP)
        {
            x = scrolltext_p->off_set + area_p->x;

            if(scrolltext_p->if_small)
                as_draw_text_clip_sf(scrolltext_p->text, x, y, &gclip, text_color);
            else
                as_draw_text_clip(scrolltext_p->text, x, y, &gclip, text_color);
        }
        else if(scrolltext_p->off_set < area_p->w - scrolltext_p->text_paint_len - AS_SCROLLTEXT_PAINT_GAP
                && scrolltext_p->off_set >= -scrolltext_p->text_paint_len)
        {
            //paint twice
            x = scrolltext_p->off_set + area_p->x;

            if(scrolltext_p->if_small)
                as_draw_text_clip_sf(scrolltext_p->text, x, y, &gclip , text_color);
            else
                as_draw_text_clip(scrolltext_p->text, x, y, &gclip , text_color);

            x += scrolltext_p->text_paint_len + AS_SCROLLTEXT_PAINT_GAP;

            if(scrolltext_p->if_small)
                as_draw_text_clip_sf(scrolltext_p->text, x, y, &gclip , text_color);
            else
                as_draw_text_clip(scrolltext_p->text, x, y, &gclip , text_color);
        }
        else
        {
            x = scrolltext_p->off_set + area_p->x + scrolltext_p->text_paint_len + AS_SCROLLTEXT_PAINT_GAP;

            if(scrolltext_p->if_small)
                as_draw_text_clip_sf(scrolltext_p->text, x, y, &gclip , text_color);
            else
                as_draw_text_clip(scrolltext_p->text, x, y, &gclip , text_color);
        }
    }
}

static void as_ctrl_scrolltext_paint(as_control* ctrl_p)
{
    as_scrolltext* scrolltext_p = (as_scrolltext*)ctrl_p;
    as_rect* area_p = NULL;
    ASINT layer, text_h;

    if(!ctrl_p || ctrl_p->if_hidden)
        return;

    area_p = &ctrl_p->area;
    layer = ctrl_p->show_hdlr;
    text_h = as_ctrl_scrolltext_get_wstr_height(scrolltext_p);

    if(layer < 0 || as_set_layer_clip_ex(layer, area_p) == AS_IGNORE
       || as_set_layer_clip_ex(layer, &scrolltext_p->valid_show_area) == AS_IGNORE)
    {
        as_reset_layer_clip(layer);
#if defined(AS_RUN_ON_SKY)
        as_reset_clip();
#endif
        return;
    }

    if(scrolltext_p->if_focused == ASTRUE)
    {
        as_ctrl_scrolltext_paint_scrolled(scrolltext_p, area_p, scrolltext_p->text_color, text_h);
    }
    else
    {
        as_ctrl_scrolltext_paint_truncated(scrolltext_p, area_p, scrolltext_p->text_color, text_h);
    }

    as_reset_layer_clip(layer);
}

static void as_ctrl_scrolltext_move(as_control* ctrl_p, ASINT x_off, ASINT y_off)
{
    as_scrolltext* scrolltext_p = (as_scrolltext*)ctrl_p;

    if(!scrolltext_p)
        return;

    scrolltext_p->base.area.x += (ASINT16)x_off;
    scrolltext_p->base.area.y += (ASINT16)y_off;

    if(scrolltext_p->bg_img)
        scrolltext_p->bg_img->base.move((as_control*)scrolltext_p->bg_img, x_off, y_off);

    if(scrolltext_p->focus_bg_img)
        scrolltext_p->focus_bg_img->base.move((as_control*)scrolltext_p->focus_bg_img, x_off, y_off);
}

static void as_ctrl_scrolltext_timer_cb(ASINT tid)
{
    ASINT i = 0;

    for (i = 0; i < AS_MAX_SCROLLTEXT_CTRLS; i++)
    {
        if(s_as_scrolltext_ctrl_store[i] && s_as_scrolltext_ctrl_store[i]->if_focused == ASTRUE
           && s_as_scrolltext_ctrl_store[i]->base.if_hidden == ASFALSE)
        {
            as_scrolltext* scrolltext_p = s_as_scrolltext_ctrl_store[i];
            scrolltext_p->base.paint_hdlr((as_control*)scrolltext_p);
            as_ctrl_flush();
            scrolltext_p->off_set -= AS_SCROLLTEXT_STEP;

            if(scrolltext_p->off_set < -(scrolltext_p->text_paint_len + AS_SCROLLTEXT_PAINT_GAP))
            {
                scrolltext_p->off_set = 0;
            }

            break;
        }
    }
}

static as_ret as_ctrl_scrolltext_set_text(as_control* ctrl_p, ASWSTR text)
{
    as_ret ret = AS_OK;
    as_scrolltext* scrolltext_p = NULL;
    ASINT len;

    if(!ctrl_p || !text)
    {
        return AS_INVALID_PARAM;
    }

    len = as_wstrlen(text);

    if(len <= 0)
        return AS_INVALID_PARAM;

    scrolltext_p = (as_scrolltext*)ctrl_p;

    if(scrolltext_p->text)
    {
        as_free(scrolltext_p->text);
        scrolltext_p->text = NULL;
    }

    scrolltext_p->text = as_calloc((len + 1) * sizeof(ASWCHAR));

    if(!scrolltext_p->text)
    {
        as_log_ctrl("<ctrl>----as_ctrl_scrolltext_change_text [no memory]");
        return AS_MEMORY_NOT_ENOUGH;
    }

    as_wstrcpy(scrolltext_p->text, text);
    scrolltext_p->text_paint_len = as_ctrl_scrolltext_get_wstr_width(scrolltext_p);

    if(scrolltext_p->text_paint_len >= scrolltext_p->base.area.w)
    {
        scrolltext_p->if_need_scroll = ASTRUE;

        if(scrolltext_p->timer_id < 0)
        {
            scrolltext_p->timer_id = as_create_timer(scrolltext_p->period, scrolltext_p->timer_cb);

            if(scrolltext_p->timer_id < 0)
            {
                scrolltext_p->if_focused = ASFALSE;
                ret = AS_RESOURCE_NOT_ENOUGH;
                return ret;
            }
        }
    }
    else
    {
        scrolltext_p->if_need_scroll = ASFALSE;

        if(scrolltext_p->timer_id > 0)
        {
            as_destroy_timer(scrolltext_p->timer_id);
            scrolltext_p->timer_id = -1;
            scrolltext_p->off_set = 0;
        }
    }

    return ret;
}

static as_ret as_ctrl_scrolltext_set_focus(as_control* ctrl_p, ASINT if_focus)
{
    as_ret ret = AS_OK;
    as_scrolltext* scrolltext_p = NULL;

    if(!ctrl_p)
    {
        ret = AS_INVALID_PARAM;
        return ret;
    }

    scrolltext_p = (as_scrolltext*)ctrl_p;
    scrolltext_p->if_focused = if_focus;

    if(scrolltext_p->if_focused == ASTRUE)
    {
        if(scrolltext_p->timer_id < 0 && scrolltext_p->text_paint_len > scrolltext_p->base.area.w)
        {
            scrolltext_p->timer_id = as_create_timer(scrolltext_p->period, scrolltext_p->timer_cb);

            if(scrolltext_p->timer_id < 0)
            {
                scrolltext_p->if_focused = ASFALSE;
                ret = AS_RESOURCE_NOT_ENOUGH;
                return ret;
            }
        }
    }
    else
    {
        if(scrolltext_p->timer_id >= 0)
        {
            as_destroy_timer(scrolltext_p->timer_id);
            scrolltext_p->timer_id = -1;
            scrolltext_p->off_set = 0;
        }
    }

    return ret;
}

static as_ret as_ctrl_scrolltext_set_text_color(as_control* ctrl_p, ASUINT text_color)
{
    as_ret ret = AS_OK;
    as_scrolltext* scrolltext_p = NULL;

    if(!ctrl_p)
    {
        ret = AS_INVALID_PARAM;
        return ret;
    }

    scrolltext_p = (as_scrolltext*)ctrl_p;
    scrolltext_p->text_color = text_color;
    return ret;
}

static as_ret as_ctrl_scrolltext_set_bg_color(as_control* ctrl_p, ASUINT bg_color)
{
    as_scrolltext* scrolltext_p = (as_scrolltext*)ctrl_p;

    if(!scrolltext_p)
    {
        return AS_INVALID_PARAM;
    }

    scrolltext_p->bg_color = bg_color;
    return AS_OK;
}

static as_ret as_ctrl_scrolltext_set_focus_bg_color(as_control* ctrl_p, ASUINT bg_color)
{
    as_scrolltext* scrolltext_p = (as_scrolltext*)ctrl_p;

    if(!scrolltext_p)
    {
        return AS_INVALID_PARAM;
    }

    scrolltext_p->focus_bg_color = bg_color;
    return AS_OK;
}

static as_ret as_ctrl_scrolltext_set_valid_show_area(as_control* ctrl_p, as_rect* rect_p)
{
    as_scrolltext* scrolltext_p = (as_scrolltext*)ctrl_p;

    if(!scrolltext_p || !rect_p)
        return AS_INVALID_PARAM;

    memcpy(&scrolltext_p->valid_show_area, rect_p, sizeof(as_rect));
    return AS_OK;
}

static as_ret as_ctrl_scrolltext_set_bg_img(as_control* ctrl_p, as_image_src_type type, ASWSTR path)
{
    as_scrolltext* scrolltext_p = (as_scrolltext*)ctrl_p;

    if(!scrolltext_p || !path)
        return AS_INVALID_PARAM;

    if(scrolltext_p->bg_img)
    {
        as_ctrl_destroy((as_control*)scrolltext_p->bg_img);
        scrolltext_p->bg_img = NULL;
    }

    scrolltext_p->bg_img = as_ctrl_image_create(scrolltext_p->base.area, type, path, ASFALSE);

    if(!scrolltext_p->bg_img)
        return AS_MEMORY_NOT_ENOUGH;

    scrolltext_p->bg_img->set_show_type((as_control*)scrolltext_p->bg_img, AS_IMAGE_TILED);
    return AS_OK;
}

static as_ret as_ctrl_scrolltext_set_focus_bg_img(as_control* ctrl_p, as_image_src_type type, ASWSTR path)
{
    as_scrolltext* scrolltext_p = (as_scrolltext*)ctrl_p;

    if(!scrolltext_p || !path)
        return AS_INVALID_PARAM;

    if(scrolltext_p->focus_bg_img)
    {
        as_ctrl_destroy((as_control*)scrolltext_p->focus_bg_img);
        scrolltext_p->focus_bg_img = NULL;
    }

    scrolltext_p->focus_bg_img = as_ctrl_image_create(scrolltext_p->base.area, type, path, ASFALSE);

    if(!scrolltext_p->focus_bg_img)
        return AS_MEMORY_NOT_ENOUGH;

    scrolltext_p->focus_bg_img->set_show_type((as_control*)scrolltext_p->focus_bg_img, AS_IMAGE_TILED);
    return AS_OK;
}

static as_ret as_ctrl_scrolltext_pause(as_control* ctrl_p)
{
    as_scrolltext* scrolltext_p = (as_scrolltext*)ctrl_p;

    if(!scrolltext_p || !scrolltext_p->if_focused || !scrolltext_p->if_need_scroll)
        return AS_INVALID_PARAM;

    if(scrolltext_p->timer_id > 0)
    {
        as_destroy_timer(scrolltext_p->timer_id);
        scrolltext_p->timer_id = -1;
    }

    scrolltext_p->if_focused  = ASFALSE;
    return AS_OK;
}

static as_ret as_ctrl_scrolltext_resume(as_control* ctrl_p)
{
    as_scrolltext* scrolltext_p = (as_scrolltext*)ctrl_p;

    if(!scrolltext_p || !scrolltext_p->if_focused || !scrolltext_p->if_need_scroll)
        return AS_INVALID_PARAM;

    if(scrolltext_p->timer_id < 0)
    {
        scrolltext_p->timer_id = as_create_timer(scrolltext_p->period, scrolltext_p->timer_cb);
    }

    return AS_OK;
}

static as_ret as_ctrl_scrolltext_set_if_small(as_control* ctrl_p, ASBOOL if_small)
{
    as_scrolltext* scrolltext_p = (as_scrolltext*)ctrl_p;

    if(!scrolltext_p || scrolltext_p->if_small == if_small)
        return AS_INVALID_PARAM;

    scrolltext_p->if_small = if_small;
    scrolltext_p->text_paint_len = as_ctrl_scrolltext_get_wstr_width(scrolltext_p);

    if(scrolltext_p->text_paint_len >= scrolltext_p->base.area.w)
        scrolltext_p->if_need_scroll = ASTRUE;
    else
        scrolltext_p->if_need_scroll = ASFALSE;

    return AS_OK;
}

static ASVOID as_ctrl_scrolltext_set_hidden(as_control* ctrl_p, ASINT if_hidden)
{
    as_scrolltext* scrolltext_p = (as_scrolltext*)ctrl_p;

    if(!ctrl_p)
        return;

    if(ctrl_p->if_hidden != if_hidden)
        ctrl_p->if_hidden = if_hidden;

    if(scrolltext_p->base.if_hidden)
    {
        scrolltext_p->pause((as_control*)scrolltext_p);
    }
    else
    {
        scrolltext_p->resume((as_control*)scrolltext_p);
    }
}

as_scrolltext* as_ctrl_scrolltext_create(as_rect area, ASWSTR text, ASUINT text_color, ASUINT bg_color)
{
    as_scrolltext* scrolltext_p = NULL;
    ASINT len;

    if(!text || as_wstrlen(text) <= 0)
    {
        return NULL;
    }

    scrolltext_p = as_calloc(sizeof(as_scrolltext));

    if(!scrolltext_p)
    {
        return scrolltext_p;
    }

    if(as_ctrl_scrolltext_store_ptr(scrolltext_p) != AS_OK)
    {
        as_free(scrolltext_p);
        scrolltext_p = NULL;
        return scrolltext_p;
    }

    len = as_wstrlen(text);
    scrolltext_p->text = as_calloc((len + 1) * sizeof(ASWCHAR));

    if(!scrolltext_p->text)
    {
        as_free(scrolltext_p);
        return NULL;
    }

    as_wstrcpy(scrolltext_p->text, text);
    as_ctrl_init((as_control*)scrolltext_p, area);
    scrolltext_p->base.move = as_ctrl_scrolltext_move;
    scrolltext_p->base.paint_hdlr = as_ctrl_scrolltext_paint;
    scrolltext_p->base.set_hidden = as_ctrl_scrolltext_set_hidden;
    scrolltext_p->base.ctrl_type = AS_CTRL_SCROLLTEXT;
    scrolltext_p->off_set = 0;
    scrolltext_p->if_focused = ASFALSE;
    scrolltext_p->text_color = text_color;
    scrolltext_p->bg_color = bg_color;
    scrolltext_p->period = 100;
    scrolltext_p->text_paint_len = as_ctrl_scrolltext_get_wstr_width(scrolltext_p);

    if(scrolltext_p->text_paint_len >= scrolltext_p->base.area.w)
        scrolltext_p->if_need_scroll = ASTRUE;

    scrolltext_p->timer_id = -1;
    scrolltext_p->timer_cb = as_ctrl_scrolltext_timer_cb;
    scrolltext_p->set_focus = as_ctrl_scrolltext_set_focus;
    scrolltext_p->set_text = as_ctrl_scrolltext_set_text;
    scrolltext_p->set_text_color = as_ctrl_scrolltext_set_text_color;
    scrolltext_p->set_bg_color = as_ctrl_scrolltext_set_bg_color;
    scrolltext_p->set_focus_bg_color = as_ctrl_scrolltext_set_focus_bg_color;
    scrolltext_p->set_bg_img = as_ctrl_scrolltext_set_bg_img;
    scrolltext_p->set_focus_bg_img = as_ctrl_scrolltext_set_focus_bg_img;
    scrolltext_p->set_valid_show_area = as_ctrl_scrolltext_set_valid_show_area;
    scrolltext_p->pause = as_ctrl_scrolltext_pause;
    scrolltext_p->resume = as_ctrl_scrolltext_resume;
    scrolltext_p->set_if_small = as_ctrl_scrolltext_set_if_small;
    return scrolltext_p;
}

as_ret as_ctrl_scrolltext_destroy(as_scrolltext* ctrl_scrolltext_p)
{
    as_ret ret = AS_OK;

    if(!ctrl_scrolltext_p)
    {
        ret = AS_INVALID_PARAM;
        return ret;
    }

    if(ctrl_scrolltext_p->text)
    {
        as_free(ctrl_scrolltext_p->text);
        ctrl_scrolltext_p->text = NULL;
    }

    if(ctrl_scrolltext_p->bg_img)
    {
        as_ctrl_destroy((as_control*)ctrl_scrolltext_p->bg_img);
        ctrl_scrolltext_p->bg_img = NULL;
    }

    if(ctrl_scrolltext_p->focus_bg_img)
    {
        as_ctrl_destroy((as_control*)ctrl_scrolltext_p->focus_bg_img);
        ctrl_scrolltext_p->focus_bg_img = NULL;
    }

    if(ctrl_scrolltext_p->timer_id > 0)
    {
        as_destroy_timer(ctrl_scrolltext_p->timer_id);
        ctrl_scrolltext_p->timer_id = -1;
        ctrl_scrolltext_p->off_set = 0;
    }

    as_ctrl_scrolltext_remove_ptr(ctrl_scrolltext_p);
    as_free(ctrl_scrolltext_p);
    return ret;
}